#ifndef __GATTS_H_
#define __GATTS_H_

#include <stdint.h>
#include <stdbool.h>

// 蓝牙核心规范定义的特征值
#define GATTS_PERM_READ (1 << 1) /* 0x02 */
#define GATTS_PERM_WRITE_NR (1 << 2) /* 0x04 */
#define GATTS_PERM_WRITE (1 << 3) /* 0x08 */
#define GATTS_PERM_NOTIFY (1 << 4) /* 0x10 */
#define GATTS_PERM_INDICATE (1 << 5) /* 0x20 */
typedef uint8_t gatts_permission_t;

struct gatts_uuid {
	uint8_t bit_len;
	union {
		uint16_t uuid16; /*!< 16bit UUID */
		uint32_t uuid32; /*!< 32bit UUID */
		uint8_t uuid128[16]; /*!< 128bit UUID */
	} uuid; /*!< UUID */
};

/**
 * @brief 获取uuid数据对应的u8指针
 * @param uuid 对应uuid
 * @return 返回u8指针
 */
uint8_t *get_uuid_u8_pointer(struct gatts_uuid *uuid);

/**
 * @brief 判断两个uuid是否相等
 * @param uuid1
 * @param uuid2
 * @return 相等返回真，否则返回假
 */
bool equal_uuid(const struct gatts_uuid *uuid1, const struct gatts_uuid *uuid2);

struct gatts_char {
	struct gatts_uuid uuid;
	uint8_t *value; /*!< Element value array*/
	uint16_t length; /*!< Current length of the element*/
	uint16_t max_length; /*!< Maximum length of the element*/
	uint16_t cccd;
	gatts_permission_t perm; /*!< Attribute permission */
};

struct gatts_service {
	struct gatts_uuid uuid;
	struct gatts_char *characteristics;
	uint8_t char_num;
};

typedef void (*read_cb_t)(const struct gatts_uuid *uuid, uint8_t *send_data,
			  uint16_t *len);

typedef void (*write_cb_t)(const struct gatts_uuid *uuid,
			   const uint8_t *recv_data, uint16_t len);

struct gatts_profile {
	const char *dev_name;
	struct gatts_service *services;
	uint8_t service_num;
	read_cb_t read_cb;
	write_cb_t write_cb;
};

typedef enum {
	GATTS_OK, // 成功
	GATTS_INDICATE_PERM_NOCNF, // 未配置indicate权限
	GATTS_NOTIFY_PERM_NOCNF, // 未配置notify权限
	GATTS_UUID_NOTFOUND, // 找不到uuid
	GATTS_LENGTH_EXCEEDS_MAXLEN, // 长度超出最大限制
} gatts_err_t;

/**
 * @brief 根据profile初始化gatts
 * @param profile
 * @return 返回错误码
 */
gatts_err_t gatts_init(struct gatts_profile *profile);

/**
 * @brief 释放gatts资源
 * @return 返回错误码
 */
gatts_err_t gatts_free();

/**
 * @brief 获取notify工作条件
 * @param profile 对应profile
 * @param uuid 对应的uuid
 * @return 返回错误码
 */
gatts_err_t gatts_get_notify_conditions(struct gatts_profile *profile,
					const struct gatts_uuid *uuid);

/**
 * @brief 获取indicate工作条件
 * @param profile 对应profile
 * @param uuid 对应的uuid
 * @return 返回错误码
 */
gatts_err_t gatts_get_indicate_conditions(struct gatts_profile *profile,
					  const struct gatts_uuid *uuid);

/**
 * @brief 以并发安全的方式设置value
 * @param uuid 对应的uuid
 * @param value 欲设置的value
 * @param len 欲设置的len
 * @return 返回错误码
 */
gatts_err_t gatts_set_value(const struct gatts_uuid *uuid, const uint8_t *value,
			    uint16_t len);

/**
 * @brief 以并发安全的方式获取value
 * @param uuid 对应的uuid
 * @param value 获取后写入的value
 * @param len 获取后写入的len,不需要可以传入NULL
 * @param max_len 允许的最大len
 * @return 返回错误码
 */
gatts_err_t gatts_get_value(const struct gatts_uuid *uuid, uint8_t *value,
			    uint16_t *len, uint16_t max_len);

/**
 * @brief 发送gatts通知
 * @param uuid 对应的uuid
 * @return 返回错误码
 */
gatts_err_t gatts_notify(const struct gatts_uuid *uuid);

/**
 * @brief 发送gatts指示
 * @param uuid 对应的uuid
 * @return 返回错误码
 */
gatts_err_t gatts_indicate(const struct gatts_uuid *uuid);

void print_uuid(const struct gatts_uuid *uuid, uint8_t tab_num);

void print_value(const uint8_t *value, uint16_t length, uint8_t tab_num);

void print_perm(const gatts_permission_t perm, uint8_t tab_num);

void print_char(struct gatts_char *c, uint8_t tab_num);

void print_service(struct gatts_service *s, uint8_t tab_num);

void print_profile(struct gatts_profile *profile, uint8_t tab_num);

#endif